using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Xml;


using Commonplace.Domain;
using Commonplace.Controller;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Runtime.Remoting;
using MediaWikiEngine.Domain;
using MediaWikiEngine;
using MediaWikiEngine.Command;

namespace Commonplace
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class MainForm : System.Windows.Forms.Form
	{
		private System.Windows.Forms.PictureBox pictureBox1;
		private System.Windows.Forms.StatusBar _status;
		private System.Windows.Forms.Panel panel1;
		private System.Windows.Forms.Button _upload;
		private System.Windows.Forms.ProgressBar _progress;
		private Commonplace.DetailList _detailList;
		private System.Windows.Forms.Button _bulk;
		private System.Windows.Forms.Button _clear;
		private System.Windows.Forms.Button _add;
		private System.Windows.Forms.OpenFileDialog _openFile;
		private System.Windows.Forms.Button _options;
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public MainForm()
		{
			//
			// Required for Windows Form Designer support
			//
            InitializeComponent();

		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
            this._status = new System.Windows.Forms.StatusBar();
            this.panel1 = new System.Windows.Forms.Panel();
            this._progress = new System.Windows.Forms.ProgressBar();
            this._upload = new System.Windows.Forms.Button();
            this._bulk = new System.Windows.Forms.Button();
            this._clear = new System.Windows.Forms.Button();
            this._add = new System.Windows.Forms.Button();
            this._openFile = new System.Windows.Forms.OpenFileDialog();
            this._options = new System.Windows.Forms.Button();
            this._detailList = new Commonplace.DetailList();
            this.pictureBox1 = new System.Windows.Forms.PictureBox();
            this.panel1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
            this.SuspendLayout();
            // 
            // _status
            // 
            this._status.Location = new System.Drawing.Point(0, 368);
            this._status.Name = "_status";
            this._status.Size = new System.Drawing.Size(552, 22);
            this._status.TabIndex = 1;
            // 
            // panel1
            // 
            this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.panel1.BackColor = System.Drawing.SystemColors.ControlDark;
            this.panel1.Controls.Add(this._progress);
            this.panel1.Controls.Add(this._upload);
            this.panel1.Location = new System.Drawing.Point(0, 312);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(552, 56);
            this.panel1.TabIndex = 2;
            // 
            // _progress
            // 
            this._progress.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this._progress.Location = new System.Drawing.Point(32, 16);
            this._progress.Name = "_progress";
            this._progress.Size = new System.Drawing.Size(368, 24);
            this._progress.TabIndex = 1;
            // 
            // _upload
            // 
            this._upload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this._upload.BackColor = System.Drawing.SystemColors.Control;
            this._upload.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this._upload.Location = new System.Drawing.Point(448, 16);
            this._upload.Name = "_upload";
            this._upload.Size = new System.Drawing.Size(75, 23);
            this._upload.TabIndex = 0;
            this._upload.Text = "&Upload";
            this._upload.UseVisualStyleBackColor = false;
            this._upload.Click += new System.EventHandler(this._upload_Click);
            // 
            // _bulk
            // 
            this._bulk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this._bulk.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this._bulk.Location = new System.Drawing.Point(456, 16);
            this._bulk.Name = "_bulk";
            this._bulk.Size = new System.Drawing.Size(80, 24);
            this._bulk.TabIndex = 3;
            this._bulk.Text = "Bulk Edit...";
            this._bulk.Click += new System.EventHandler(this._bulk_Click);
            // 
            // _clear
            // 
            this._clear.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this._clear.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this._clear.Location = new System.Drawing.Point(368, 16);
            this._clear.Name = "_clear";
            this._clear.Size = new System.Drawing.Size(75, 23);
            this._clear.TabIndex = 2;
            this._clear.Text = "&Clear Files";
            this._clear.Click += new System.EventHandler(this._clear_Click);
            // 
            // _add
            // 
            this._add.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this._add.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this._add.Location = new System.Drawing.Point(280, 16);
            this._add.Name = "_add";
            this._add.Size = new System.Drawing.Size(75, 23);
            this._add.TabIndex = 1;
            this._add.Text = "&Add Files";
            this._add.Click += new System.EventHandler(this._add_Click);
            // 
            // _openFile
            // 
            this._openFile.Filter = "All Files|*.*|All Images|*.jpg;*.jpeg;*.png;*.gif|JPEG images|*.jpg;*.jpeg|GIF im" +
                "ages|*.gif|PNG images|*.png";
            this._openFile.Multiselect = true;
            // 
            // _options
            // 
            this._options.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this._options.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this._options.Location = new System.Drawing.Point(192, 16);
            this._options.Name = "_options";
            this._options.Size = new System.Drawing.Size(75, 23);
            this._options.TabIndex = 0;
            this._options.Text = "&Options";
            this._options.Click += new System.EventHandler(this._options_Click);
            // 
            // _detailList
            // 
            this._detailList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this._detailList.BackColor = System.Drawing.SystemColors.ControlLight;
            this._detailList.LayoutSuspended = false;
            this._detailList.Location = new System.Drawing.Point(0, 72);
            this._detailList.Name = "_detailList";
            this._detailList.Size = new System.Drawing.Size(552, 240);
            this._detailList.TabIndex = 4;
            // 
            // pictureBox1
            // 
            this.pictureBox1.Image = global::Commonplace.Properties.Resources.CommonplaceLogo;
            this.pictureBox1.Location = new System.Drawing.Point(8, 8);
            this.pictureBox1.Name = "pictureBox1";
            this.pictureBox1.Size = new System.Drawing.Size(50, 50);
            this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
            this.pictureBox1.TabIndex = 0;
            this.pictureBox1.TabStop = false;
            // 
            // MainForm
            // 
            this.AllowDrop = true;
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(552, 390);
            this.Controls.Add(this._options);
            this.Controls.Add(this._add);
            this.Controls.Add(this._clear);
            this.Controls.Add(this._bulk);
            this.Controls.Add(this._detailList);
            this.Controls.Add(this.panel1);
            this.Controls.Add(this._status);
            this.Controls.Add(this.pictureBox1);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.MinimumSize = new System.Drawing.Size(464, 304);
            this.Name = "MainForm";
            this.Text = "Wikimedia Commonplace";
            this.DragDrop += new System.Windows.Forms.DragEventHandler(this.MainForm_DragDrop);
            this.DragEnter += new System.Windows.Forms.DragEventHandler(this.MainForm_DragEnter);
            this.Load += new System.EventHandler(this.MainForm_Load);
            this.panel1.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
            this.ResumeLayout(false);

		}
		#endregion

		private void MainForm_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
		{
			string[] fnames = (string[]) e.Data.GetData("FileDrop");

			foreach (string filename in fnames)
			{
				AddFile(filename);
			}
		}

		private void AddFile(string filename)
		{
			foreach (DetailRecord detail in _detailList.Details)
			{
				if (detail.Filename == filename)
				{
					MessageBox.Show(string.Format("File {0} already in list.", filename));
					return;
				}
			}

			try
			{
                Type detailType = FileTypeRecognizer.Instance.GetFileType(filename);

                DetailRecord record = Activator.CreateInstance(detailType) as DetailRecord;
                record.Filename = filename;

				if (true == CachedConfig.Instance.WatchPages)
					record.Watch = true;

				_detailList.AddFile(record);
			}
			catch (ArgumentException)
			{
				//ignore -- must mean it's not a recognized file
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.ToString());
			}
		}

		private void MainForm_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
		{
			if (true == e.Data.GetDataPresent("FileDrop"))
				e.Effect = DragDropEffects.Copy;
		}

		private void _upload_Click(object sender, System.EventArgs e)
		{
            _status.Text = string.Empty;

			List<DetailRecord> details = _detailList.Details;
			if (details.Count < 1)
			{
				MessageBox.Show("There are no files to upload!");
				return;
			}

			int incompleteRecords = 0;
			int filesToUpload = 0;

			foreach (DetailRecord detail in details)
			{
				if (false == detail.Uploaded)
				{
					filesToUpload++;
				
					if (false == detail.RecordComplete)
						incompleteRecords++;
				}
			}

			if (incompleteRecords > 0)
			{
				MessageBox.Show(string.Format("There {0} {1} incomplete record{2}.  Please make sure to fill out the description, source, and author information.", (incompleteRecords == 1) ? "is" : "are", incompleteRecords, (incompleteRecords == 1) ? "" : "s"));
				return;
			}

			if (filesToUpload < 1)
			{
				MessageBox.Show("All files have already been uploaded!");
				return;
			}

			string username = "";
			string password = "";

			StoredConfig config = new StoredConfig();
			username = config["username"];
			password = config["password"];

			if (username.Length < 1)
			{            
				using (LoginPopup login = new LoginPopup())
				{
					DialogResult res = login.ShowDialog(this);

					if (DialogResult.OK != res)
					{
						return;
					}
					else
					{
						username = login.Username;
						password = login.Password;

						if (username.Length < 1)
						{
							MessageBox.Show("You need to specify a username!");
							return;
						}

						if (true == login.RememberLogin)
						{
							config["username"] = username;
							config["password"] = password;
							config.Save();
						}
						else
						{
							config["username"] = null;
							config["password"] = null;
							config.Save();
						}

                        CachedConfig.Instance.Refresh();

					}
				}
			}

			UploadFiles(username, password, _detailList.Details);

		}

		private void UploadFiles(string username, string password, List<DetailRecord> details)
		{
            WikiConnection.WikiEndpoint.BaseAddress = CachedConfig.Instance.WikiConnection.BasePath;

            InteractiveCommand cmd = new InteractiveCommand(new WikiConnection(CachedConfig.Instance.WikiConnection.Hostname));
            LoginResult login = cmd.Login(username, password);
            if (false == login.LoginSuccess)
            {
                //let's clear the config
                StoredConfig config = new StoredConfig();
                config["username"] = null;
                config["password"] = null;
                config.Save();
                CachedConfig.Instance.Refresh();

                MessageBox.Show("Sorry, your login was incorrect.  Please try again with a different username and password.");
                return;
            }

            List<DetailRecord> existingRecords = new List<DetailRecord>();

            _progress.Minimum = 0;
            _progress.Maximum = details.Count;

            int uploadedCount = 0;
            int totalUploadedCount = 0;

			foreach (DetailRecord detail in details)
			{
                if (false == detail.Uploaded)
                {
                    UploadResult result = UploadFile(cmd, detail, false);

                    if (UploadResult.Uploaded == result)
                        uploadedCount++;
                    else if (UploadResult.AlreadyExists == result)
                        existingRecords.Add(detail);
                }

                _progress.Increment(1);
			}

            _status.Text = string.Format("{0} file{1} uploaded", uploadedCount, uploadedCount == 1 ? "" : "s");
            totalUploadedCount = uploadedCount;

            if (existingRecords.Count > 0)
            {
                ActionResultForm.ActionResult actionResult = ActionResultForm.ActionResult.No;
                using (ActionResultForm messageList = new ActionResultForm())
                {
                    messageList.Message = "The files below were not uploaded because they already exist on the wiki.  Would you like to overwrite the existing files and upload them anyway?";
                    List<string> fileList = new List<string>();
                    existingRecords.ForEach(delegate(DetailRecord item) { fileList.Add(string.Format("{0} ({1})", item.Name, item.Filename)); });
                    messageList.List = fileList;
                    messageList.ShowDialog();
                    actionResult = messageList.Result;
                }

                if (ActionResultForm.ActionResult.No != actionResult)
                {
                    bool confirmEachFile = (ActionResultForm.ActionResult.OneByOne == actionResult);


                    _progress.Minimum = 0;
                    _progress.Maximum = existingRecords.Count;
                    _progress.Value = 0;

                    uploadedCount = 0;

                    foreach (DetailRecord detail in existingRecords)
                    {
                        if (false == detail.Uploaded)
                        {
                            bool confirmed = true;

                            if (true == confirmEachFile)
                            {
                                DialogResult confirmationResult = MessageBox.Show(string.Format("File {0} already exists on the wiki.  Upload and overwrite?", detail.Name), "Commonplace", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

                                if (DialogResult.Yes == confirmationResult)
                                    confirmed = true;
                            }

                            if (true == confirmed)
                            {

                                UploadResult result = UploadFile(cmd, detail, true);

                                if (UploadResult.Uploaded == result)
                                    uploadedCount++;
                            }
                        }

                        _progress.Increment(1);
                    }

                    _status.Text = string.Format("{0} file{1} uploaded", uploadedCount, uploadedCount == 1 ? "" : "s");

                    totalUploadedCount += uploadedCount;
                }
            }

            if (totalUploadedCount > 0)
            {
                DialogResult res = MessageBox.Show("Clear all uploaded files from the list?", "Commonplace", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (DialogResult.Yes == res)
                {
                    List<DetailRecord> uploaded = new List<DetailRecord>();
                    details.ForEach(delegate(DetailRecord item) { if (true == item.Uploaded) uploaded.Add(item); });
                    uploaded.ForEach(delegate(DetailRecord item) { _detailList.Remove(item); });
                }
            }

            
			_progress.Value = 0;

		}

        public enum UploadResult
        {
            NotUploaded,
            AlreadyExists,
            Uploaded
        }

        private UploadResult UploadFile(InteractiveCommand cmd, DetailRecord detail, bool overrideExistingFiles)
        {
            string extension = System.IO.Path.GetExtension(detail.Filename).ToLower();
            string mimetype = FileTypeRecognizer.Instance.GetMimeType(extension);
            string pagename = string.Format("{0}{1}", detail.Name.Replace(" ", "_"), extension.ToLower());

            //check if file exists already
            string title = string.Format("Image:{0}", pagename);
            GetPageResult getPage = cmd.GetPage("Main", title);

            if (true == getPage.Page.Exists && false == overrideExistingFiles)
                return UploadResult.AlreadyExists;

            string description = string.Empty;
            if (true == CachedConfig.Instance.UseInfoTemplate)
                description = detail.InformationTemplate;
            else
                description = detail.RecordDescription;
            string licenseData = string.Empty;
            foreach (License license in CachedConfig.Instance.Licenses)
            {
                if (license.Name == detail.License)
                {
                    licenseData = license.Data;
                    break;
                }
            }

            UploadFileResult uploadFile = cmd.UploadFile(detail.Filename, mimetype, pagename, description, licenseData);
            detail.Uploaded = true;

            return UploadResult.Uploaded;

        }


		private void _bulk_Click(object sender, System.EventArgs e)
		{
			using (BulkPopulatePopup bulk = new BulkPopulatePopup())
			{
				if (DialogResult.OK == bulk.ShowDialog(this))
				{
					DetailRecord record = bulk.BulkRecord;

					int fileNumber = 1;

					foreach (DetailRecord detail in _detailList.Details)
					{
						if (record.Name.Length > 0)
							detail.Name = string.Format("{0} {1}", record.Name, fileNumber++);

						if (record.Description.Length > 0)
							detail.Description = record.Description;

						if (record.Source.Length > 0)
							detail.Source = record.Source;

						if (record.Categories.Length > 0)
							detail.Categories = record.Categories;

						if (record.License.Length > 0)
							detail.License = record.License;

                        if (record.Author.Length > 0)
                            detail.Author = record.Author;

                        if (record.Date.Length > 0)
                            detail.Date = record.Date;

						if (true == bulk.WatchSet)
							detail.Watch = record.Watch;
					}
				}
			}

		}


		private void _clear_Click(object sender, System.EventArgs e)
		{
			_detailList.ClearFiles();
		}

		private void _add_Click(object sender, System.EventArgs e)
		{
            _openFile.Filter = FileTypeRecognizer.Instance.FileSelectionMask;

			if (DialogResult.OK == _openFile.ShowDialog(this))
			{
                _detailList.LayoutSuspended = true;
                _status.Text = "Loading files...";
                _progress.Minimum = 0;
                _progress.Maximum = _openFile.FileNames.Length;
                _progress.Value = 0;
				foreach (string filename in _openFile.FileNames)
				{
					AddFile(filename);
                    _progress.Increment(1);
                    Refresh();
                    Application.DoEvents();
				}
                _detailList.LayoutSuspended = false;
                _progress.Value = 0;
                _status.Text = string.Empty;
			}

		}

		private void _options_Click(object sender, System.EventArgs e)
		{
			using (OptionsDialog options = new OptionsDialog())
			{
				if (DialogResult.OK == options.ShowDialog(this))
				{
					options.SaveConfig();
					CachedConfig.Instance.Refresh();
				}
			}
		}

		private void MainForm_Load(object sender, System.EventArgs e)
		{
            //if first-time load (no config file), load licenses
            StoredConfig config = new StoredConfig();
            if (false == config.HasSavedConfiguration)
            {
                List<License> licenses = LicenseLoader.LoadLicenses(CachedConfig.Instance.WikiConnection);
                List<string> licenseData = new List<string>();
                licenses.ForEach(delegate(License item) { licenseData.Add(item.Data); });

                config.UpdateList("licenses", licenseData);
                config.Save();

                CachedConfig.Instance.Refresh();
            }


			if (true == CachedConfig.Instance.Autoupdate)
			{
				AutoUpdate au = new AutoUpdate();
				au.GetNewFile();
			}
		}
	}
}
